package so.wy.servicecenter.businessbed.manager.normal;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import so.wdl.framework.core.date.DateTime;
import so.wdl.framework.core.date.DateUtil;
import so.wy.servicecenter.base.exception.ManagerException;
import so.wy.servicecenter.base.frame.manager.AbstractManager;
import so.wy.servicecenter.businessbed.dao.enums.StatusPayEnum;
import so.wy.servicecenter.businessbed.dao.enums.TypePayBusinessEnum;
import so.wy.servicecenter.businessbed.dao.enums.TypePayEnum;
import so.wy.servicecenter.businessbed.dao.enums.TypePayTransactionEnum;
import so.wy.servicecenter.businessbed.dao.rdb.deposit.DepositDAO;
import so.wy.servicecenter.businessbed.dao.rdb.deposit.DepositDO;
import so.wy.servicecenter.businessbed.dao.rdb.order.order.OrderDO;
import so.wy.servicecenter.businessbed.dao.rdb.pay.PayDAO;
import so.wy.servicecenter.businessbed.dao.rdb.pay.PayDO;
import so.wy.servicecenter.businessbed.dao.rdb.rent_user.RentUserDO;
import so.wy.servicecenter.businessbed.extend.UserAppOutManager;
import so.wy.servicecenter.businessbed.manager.utils.OrderUtils;
import so.wy.servicecenter.data.dao.enums.YesNoEnum;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

@Service
@Scope("prototype")
public class WxPayOptManager extends AbstractManager {
    @Autowired
    private PayDAO payDAO;

    @Autowired
    private UserAppOutManager userAppOutManager;

    @Autowired
    private DepositDAO depositDAO;

    @Value("${wx.pay.payNotifyUrl}")
    private String wxPayNotifyUrl;

    @Value("${wx.pay.refundNotifyUrl}")
    private String refundNotifyUrl;

    @Autowired
    private WxPayService wxPayService;

    //订单预支付
    public WxPayMpOrderResult createOrderPrePay(RentUserDO rentUser, OrderDO order) throws ManagerException {
        String payTradeNo = OrderUtils.genPayPreOrderNum();
        try {
            WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder()
                    .spbillCreateIp("127.0.0.1")
                    .notifyUrl(wxPayNotifyUrl)
                    .tradeType("JSAPI")
                    .openid(userAppOutManager.getUserOpenId(rentUser.getUserId()))
                    .body("租赁订单支付")
                    .outTradeNo(payTradeNo)
                    .totalFee(convet2WxMoney(order.getOrderAmount()))
                    .build();

            PayDO payDO = new PayDO();
            payDO.setPayType(TypePayEnum.INCOME.getCode());
            payDO.setTransactionType(TypePayTransactionEnum.PAY.getCode());
            payDO.setBusinessType(TypePayBusinessEnum.ORDER.getCode());
            payDO.setBusinessSign(order.getOrderSerial());
            payDO.setPreOrderSerial(payTradeNo);
            payDO.setPayerName(rentUser.getRentUserName());
            payDO.setReceiverName("大有云享");
            payDO.setPayDesc("租赁订单支付");
            payDO.setOptTime(new Date());
            payDO.setTransactionAmount(order.getOrderAmount().doubleValue());
            payDO.setPayStatus(StatusPayEnum.PROCESSING.getCode());
            payDO.setRentUserId(rentUser.getRentUserId());
            payDAO.insert(payDO);


            return wxPayService.createOrder(request);
        } catch (WxPayException e) {
            logger.error("微信支付异常：" + JSON.toJSONString(e));
            throw exception("微信支付异常", e);
        }
    }

    //押金充值
    public WxPayMpOrderResult createTopUpPrePay(RentUserDO rentUser) throws ManagerException {
        String payTradeNo = OrderUtils.genPayPreOrderNum();
        BigDecimal fee = getDeposit();
        try {
            WxPayUnifiedOrderRequest request = WxPayUnifiedOrderRequest.newBuilder()
                    .spbillCreateIp("127.0.0.1")
                    .notifyUrl(wxPayNotifyUrl)
                    .tradeType("JSAPI")
                    .openid(userAppOutManager.getUserOpenId(rentUser.getUserId()))
                    .body("押金充值")
                    .outTradeNo(payTradeNo)
                    .totalFee(convet2WxMoney(fee))
                    .build();

            PayDO payDO = new PayDO();
            payDO.setPayType(TypePayEnum.INCOME.getCode());
            payDO.setTransactionType(TypePayTransactionEnum.TOPUP.getCode());
            payDO.setBusinessType(TypePayBusinessEnum.DEPOSIT.getCode());
            payDO.setBusinessSign("");
            payDO.setPreOrderSerial(payTradeNo);
            payDO.setPayerName(rentUser.getRentUserName());
            payDO.setReceiverName("大有云享");
            payDO.setPayDesc("押金充值");
            payDO.setOptTime(new Date());
            payDO.setTransactionAmount(fee.doubleValue());
            payDO.setPayStatus(StatusPayEnum.PROCESSING.getCode());
            payDO.setRentUserId(rentUser.getRentUserId());
            payDAO.insert(payDO);


            return wxPayService.createOrder(request);
        } catch (WxPayException e) {
            logger.error("微信支付异常：" + JSON.toJSONString(e));
            throw exception("微信支付异常", e);
        }
    }

    //押金提现
    public void rechargeTopUpPrePay(RentUserDO rentUser) throws ManagerException {
        DateTime dateTime = DateUtil.offsetMonth(new Date(), -1);
        PageHelper.startPage(1,1);
        List<PayDO> payDOs = payDAO.selectList(new LambdaQueryWrapper<PayDO>()
                .eq(PayDO::getBusinessType, TypePayBusinessEnum.DEPOSIT.getCode())
                .eq(PayDO::getPayStatus, StatusPayEnum.SUCCESS.getCode())
                .eq(PayDO::getPayType, TypePayEnum.INCOME.getCode())
                .eq(PayDO::getRentUserId, rentUser.getRentUserId())
                .gt(PayDO::getOptTime, dateTime)
                .orderByDesc(PayDO::getOptTime));

        if (payDOs == null || payDOs.size()<1){
            throw exception("数据异常，请联系客服人员");
        }

        PayDO payDO = payDOs.get(0);
        String payTradeNo = OrderUtils.genPayPreOrderNum();

        //获取支付押金的单号
        WxPayRefundRequest refundRequest = WxPayRefundRequest.newBuilder()
                .outTradeNo(payDO.getPreOrderSerial())
                .outRefundNo(payTradeNo)
                .totalFee(convet2WxMoney(BigDecimal.valueOf(payDO.getTransactionAmount())))
                .refundFee(convet2WxMoney(BigDecimal.valueOf(payDO.getTransactionAmount())))
                .notifyUrl(refundNotifyUrl)
                .refundDesc("押金提现")
                .build();

        //插入数据
        PayDO refrendDO = new PayDO();
        refrendDO.setPayType(TypePayEnum.PAY.getCode());
        refrendDO.setTransactionType(TypePayTransactionEnum.WITHDRAW.getCode());
        refrendDO.setBusinessType(TypePayBusinessEnum.DEPOSIT.getCode());
        refrendDO.setBusinessSign("");
        refrendDO.setPreOrderSerial(payTradeNo);
        refrendDO.setPayerName("大有云享");
        refrendDO.setReceiverName(rentUser.getRentUserName());
        refrendDO.setPayDesc("押金提现");
        refrendDO.setOptTime(new Date());
        refrendDO.setTransactionAmount(payDO.getTransactionAmount());
        refrendDO.setPayStatus(StatusPayEnum.PROCESSING.getCode());
        refrendDO.setRentUserId(rentUser.getRentUserId());

        try {
            wxPayService.refund(refundRequest);
        } catch (WxPayException e) {
            refrendDO.setPayStatus(StatusPayEnum.FAIL.getCode());
            throw exception("微信退款异常");
        }finally {
            payDAO.insert(refrendDO);
        }
    }


    private int convet2WxMoney(BigDecimal platMoney) {
        return platMoney.multiply(new BigDecimal(100)).intValue();
    }

    private BigDecimal getDeposit() throws ManagerException {
        DepositDO depositDO = depositDAO.selectOne(new LambdaQueryWrapper<DepositDO>()
                .eq(DepositDO::getIsOpen, YesNoEnum.YES.getCode()));

        if (depositDO == null){
            throw exception("未设置押金");
        }

        return depositDO.getDepositAmount();
    }
}
